Vadovas kūrėjams ir inžinieriams, kaip audituoti TypeScript kodą dėl įprastų pažeidžiamumų (XSS, SQLi ir kt.), naudojant SAST, DAST ir SCA.
TypeScript saugumo auditas: Išsamus pažeidžiamumo tipų nustatymo gilinimasis
TypeScript užvaldė kūrimo pasaulį, siūlydamas statinio tipavimo tvirtumą kartu su JavaScript lankstumu. Jis naudojamas viskam – nuo sudėtingų sąsajos programų su sistemomis, tokiomis kaip Angular ir React, iki didelio našumo vidinės dalies paslaugų su Node.js. Nors TypeScript kompiliatorius puikiai aptinka su tipais susijusias klaidas ir gerina kodo kokybę, labai svarbu suprasti esminę tiesą: TypeScript nėra stebuklinga saugumo kulka.
Tipų sauga apsaugo nuo tam tikros klasės klaidų, tokių kaip nulinio žymeklio išimtys arba neteisingų duomenų tipų perdavimas funkcijoms. Tačiau ji savaime neužkerta kelio loginėms saugumo spragoms. Pažeidžiamumai, tokie kaip kryžminio puslapio scenarijaus vykdymas (XSS), SQL injekcija (SQLi) ir sugadinta prieigos kontrolė, kyla dėl programos logikos ir duomenų tvarkymo, sričių, kurios nepriklauso tiesioginei tipų tikrintuvo kompetencijai. Būtent čia saugumo auditas tampa nepakeičiamas.
Šis išsamus vadovas skirtas pasaulinei kūrėjų, saugumo specialistų ir inžinerijos vadovų auditorijai. Išnagrinėsime TypeScript saugumo kraštovaizdį, pasinersime į dažniausiai pasitaikančius pažeidžiamumo tipus ir pateiksime veiksmingas strategijas, kaip juos aptikti ir sušvelninti naudojant statinės analizės (SAST), dinaminės analizės (DAST) ir programinės įrangos sudėties analizės (SCA) derinį.
„TypeScript“ saugumo aplinkos supratimas
Prieš pradedant nagrinėti konkrečius aptikimo metodus, svarbu apibrėžti tipinės „TypeScript“ programos saugumo kontekstą. Šiuolaikinė programa yra sudėtinga pirminio kodo, trečiųjų šalių bibliotekų ir infrastruktūros konfigūracijų sistema. Bet kurio iš šių sluoksnių pažeidžiamumas gali sukelti visos sistemos kompromitavimą.
Kodėl tipų saugumo nepakanka
Apsvarstykite šį paprastą „Express.js“ kodo fragmentą „TypeScript“ kalba:
import express from 'express';
import { db } from './database';
const app = express();
app.get('/user', async (req, res) => {
const userId: string = req.query.id as string;
// The type is correct, but the logic is flawed!
const query = `SELECT * FROM users WHERE id = '${userId}'`;
const user = await db.query(query);
res.json(user);
});
„TypeScript“ kompiliatoriaus požiūriu, šis kodas yra visiškai tinkamas. „userId“ yra teisingai nurodytas kaip „string“ tipas. Tačiau saugumo požiūriu, jame yra klasikinė SQL injekcijos pažeidžiamumo. Atakuotojas galėtų pateikti „userId“, pavyzdžiui, ' OR 1=1; --, kad apeitų autentifikavimą ir gautų visus vartotojus iš duomenų bazės. Tai iliustruoja spragą, kurią turi užpildyti saugumo auditas: analizuoti duomenų srautą ir tvarkymą, o ne tik jų tipą.
Dažni atakų vektoriai „TypeScript“ programose
Daugelis „JavaScript“ programose aptinkamų pažeidžiamumų yra vienodai paplitę ir „TypeScript“ programose. Atliekant auditą, naudinga paiešką pagrįsti nusistovėjusiomis kategorijomis, tokiomis kaip OWASP Top 10:
- Injekcija: SQLi, NoSQLi, komandų injekcija ir žurnalų injekcija, kai nepatikimi duomenys siunčiami interpretatoriui kaip komandos ar užklausos dalis.
- Kryžminio puslapio scenarijaus vykdymas (XSS): Išsaugotas, atspindėtas ir DOM pagrindu veikiantis XSS, kai nepatikimi duomenys įtraukiami į tinklalapį be tinkamo išskyrimo.
- Nesaugus deserializavimas: Deserializuojant nepatikimus duomenis, gali atsirasti nuotolinio kodo vykdymo (RCE) galimybė, jei programos logika gali būti manipuliuojama.
- Sugadinta prieigos kontrolė: Leidimų vykdymo trūkumai, leidžiantys vartotojams pasiekti duomenis arba atlikti veiksmus, kurių jie neturėtų.
- Jautrių duomenų atskleidimas: Užkoduotos paslaptys (API raktai, slaptažodžiai), silpna kriptografija arba jautrių duomenų atskleidimas žurnaluose ar klaidų pranešimuose.
- Komponentų su žinomais pažeidžiamumais naudojimas: Pasikliavimas trečiųjų šalių „npm“ paketais su dokumentuotais saugumo trūkumais.
Statinės analizės saugumo testavimas (SAST) „TypeScript“ kalboje
Statinės analizės saugumo testavimas, arba SAST, apima programos šaltinio kodo analizę dėl saugumo pažeidžiamumų, jo nevykdant. Sudėtinei kalbai, tokiai kaip „TypeScript“, tai yra neįtikėtinai galingas metodas, nes galime panaudoti kompiliatoriaus infrastruktūrą.
„TypeScript“ abstraktus sintaksės medis (AST) ir jo galia
Kai „TypeScript“ kompiliatorius apdoroja jūsų kodą, jis pirmiausia sukuria abstraktų sintaksės medį (AST). AST yra medžio pavidalo kodo struktūros atvaizdavimas. Kiekvienas medžio mazgas atspindi konstrukciją, pvz., kintamojo deklaraciją, funkcijos iškvietimą ar dvejetainę išraišką. Programiškai naršydami šį medį, SAST įrankiai gali suprasti kodo logiką ir, kas dar svarbiau, atsekti duomenų srautą.
Tai leidžia mums atlikti užterštumo analizę: nustatyti, kur nepatikimi vartotojo įvesties duomenys („šaltinis“) pereina per programą ir pasiekia potencialiai pavojingą funkciją („išteklius“) be tinkamo valymo ar patvirtinimo.
Pažeidžiamumo šablonų aptikimas naudojant SAST
Injekcijos trūkumai (SQLi, NoSQLi, komandų injekcija)
- Šablonas: Ieškokite vartotojo kontroliuojamos įvesties, tiesiogiai sujungtos arba interpoliuotos į eilutes, kurias vėliau vykdo duomenų bazės tvarkyklė, apvalkalas ar kitas interpretatorius.
- Šaltiniai (užterštumo kilmė): „req.body“, „req.query“, „req.params“ „Express/Koa“, „process.argv“, failų skaitymas.
- Išteklius (pavojingos funkcijos): „db.query()“, „Model.find()“, „child_process.exec()“, „eval()“.
- Pažeidžiamumo pavyzdys (SQLi):
// SOURCE: req.query.category is untrusted user input const category: string = req.query.category as string; // SINK: The category variable flows into the database query without sanitization const products = await db.query(`SELECT * FROM products WHERE category = '\${category}'`); - Aptikimo strategija: SAST įrankis atseks „category“ kintamąjį nuo jo šaltinio („req.query“) iki ištekliaus („db.query“). Jei jis aptinka, kad kintamasis yra dalis eilutės šablono, perduodamo į išteklių, jis pažymi potencialų injekcijos pažeidžiamumą. Pataisymas yra naudoti parametrizuotas užklausas, kai duomenų bazės tvarkyklė tinkamai tvarko išskyrimą.
Kryžminio puslapio scenarijaus vykdymas (XSS)
- Šablonas: Nepatikimi duomenys atvaizduojami DOM, be tinkamo išskyrimo HTML kontekstui.
- Šaltiniai: Bet kokie vartotojo pateikti duomenys iš API, formų ar URL parametrų.
- Išteklius: „element.innerHTML“, „document.write()“, React „dangerouslySetInnerHTML“, Vue „v-html“.
- Pažeidžiamumo pavyzdys (React):
function UserComment({ commentText }: { commentText: string }) { // SOURCE: commentText comes from an external source // SINK: dangerouslySetInnerHTML writes raw HTML to the DOM return ; } - Aptikimo strategija: Audito procesas apima visų šių nesaugių DOM manipuliavimo išteklių naudojimo nustatymą. Tuomet įrankis atlieka atvirkštinę duomenų srauto analizę, kad nustatytų, ar duomenys kilę iš nepatikimo šaltinio. Šiuolaikinės sąsajos sistemos, tokios kaip React ir Angular, pagal numatytuosius nustatymus teikia automatinį išskyrimą, todėl pagrindinis dėmesys turėtų būti skiriamas sąmoningiems pakeitimams, tokiems kaip parodytas aukščiau.
Nesaugus deserializavimas
- Šablonas: Programa naudoja funkciją, skirtą deserializuoti duomenis iš nepatikimo šaltinio, kas potencialiai gali inicijuoti savavališkas klases arba vykdyti kodą.
- Šaltiniai: Vartotojo kontroliuojami slapukai, API duomenų paketai arba iš failo skaityti duomenys.
- Išteklius: Funkcijos iš nesaugių bibliotekų, tokių kaip „node-serialize“, „serialize-javascript“ (tam tikrose konfigūracijose) arba pasirinktinė deserializavimo logika.
- Pažeidžiamumo pavyzdys:
import serialize from 'node-serialize'; app.post('/profile', (req, res) => { // SOURCE: req.body.data is fully controlled by the user const userData = Buffer.from(req.body.data, 'base64').toString(); // SINK: Insecure deserialization can lead to RCE const obj = serialize.unserialize(userData); // ... process obj }); - Aptikimo strategija: SAST įrankiai saugo žinomų nesaugių deserializavimo funkcijų sąrašą. Jie nuskaito kodo bazę, ieškodami bet kokių iškvietimų šioms funkcijoms ir juos pažymi. Pagrindinis rizikos mažinimas yra vengti nepatikimų duomenų deserializavimo arba naudoti saugius, tik duomenų formatus, tokius kaip JSON su „JSON.parse()“.
Dinaminės analizės saugumo testavimas (DAST) „TypeScript“ programoms
Nors SAST analizuoja kodą iš vidaus, dinaminės analizės saugumo testavimas (DAST) veikia iš išorės. DAST įrankiai sąveikauja su veikiančia programa – paprastai paruošimo ar testavimo aplinkoje – ir ieško joje pažeidžiamumų taip, kaip tai darytų tikras atakuotojas. Jie neturi informacijos apie šaltinio kodą.
Kodėl DAST papildo SAST
DAST yra būtinas, nes jis gali aptikti problemas, kurių SAST gali nepastebėti, pavyzdžiui:
- Aplinkos ir konfigūracijos problemos: Neteisingai sukonfigūruotas serveris, neteisingos HTTP saugumo antraštės arba atskleisti administratoriaus galiniai taškai.
- Vykdymo laiko pažeidžiamumai: Trūkumai, kurie pasireiškia tik programai veikiant ir sąveikaujant su kitomis paslaugomis, pvz., duomenų baze ar talpyklos sluoksniu.
- Sudėtingi verslo logikos trūkumai: Problemos daugiapakopiuose procesuose (pvz., atsiskaitymo sraute), kuriuos sunku modeliuoti vien tik statine analize.
DAST metodai „TypeScript“ API ir žiniatinklio programoms
API galinių taškų „Fuzzing“
„Fuzzing“ apima didelio kiekio netikėtų, sugadintų ar atsitiktinių duomenų siuntimą API galiniams taškams, siekiant pamatyti, kaip programa reaguoja. „TypeScript“ vidinei daliai tai galėtų reikšti:
- Giliai įdėto JSON objekto siuntimą POST galiniam taškui, siekiant patikrinti NoSQL injekciją ar išteklių išsekimą.
- Eilučių siuntimą ten, kur tikimasi skaičių, arba sveikųjų skaičių ten, kur tikimasi loginių, siekiant atskleisti prastą klaidų tvarkymą, kuris gali nutekėti informaciją.
- Specialiųjų simbolių (
',",<,>) įterpimą į visus parametrus, siekiant patikrinti injekcijos ir XSS trūkumus.
Tikrų atakų imitavimas
DAST skaitytuvas turės žinomų atakų duomenų paketų biblioteką. Kai jis aptinka įvesties laukelį ar API parametrą, jis sistemingai įterps šiuos duomenų paketus ir analizuos programos atsaką.
- SQLi atveju: Jis gali siųsti duomenų paketą, pvz.,
1' UNION SELECT username, password FROM users--. Jei atsake yra jautrių duomenų, galinis taškas yra pažeidžiamas. - XSS atveju: Jis gali siųsti
. Jei atsakomasis HTML kodas turi šią tikslią, neišskirtą eilutę, tai rodo atspindėto XSS pažeidžiamumą.
SAST, DAST ir SCA derinimas visapusiškam padengimui
Nei SAST, nei DAST vieni savaime nepakanka. Brandi saugumo audito strategija apima abu šiuos metodus, kartu su esminiu trečiuoju komponentu: programinės įrangos sudėties analize (SCA).
Programinės įrangos sudėties analizė (SCA): Tiekimo grandinės problema
Node.js ekosistema, kuri yra daugelio „TypeScript“ vidinės dalies kūrimo pagrindas, labai priklauso nuo atvirojo kodo paketų iš „npm“ registro. Vienas projektas gali turėti šimtus ar net tūkstančius tiesioginių ir netiesioginių priklausomybių. Pažeidžiamumas bet kuriame iš šių paketų yra pažeidžiamumas jūsų programoje.
SCA įrankiai veikia nuskaitydami jūsų priklausomybių manifestų failus („package.json“ ir „package-lock.json“ arba „yarn.lock“). Jie lygina naudojamų paketų versijas su pasauline žinomų pažeidžiamumų duomenų baze (pvz., „GitHub Advisory Database“).
Esminiai SCA įrankiai:
- „npm audit“ / „yarn audit“: Įmontuotos komandos, kurios suteikia greitą būdą patikrinti, ar nėra pažeidžiamų priklausomybių.
- „GitHub Dependabot“: Automatiškai nuskaito saugyklas ir sukuria įkėlimo užklausas, kad atnaujintų pažeidžiamas priklausomybes.
- „Snyk Open Source“: Populiarus komercinis įrankis, teikiantis išsamią informaciją apie pažeidžiamumus ir patarimus, kaip juos pašalinti.
„Shift Left“ saugumo modelio įgyvendinimas
„Perkėlimas į kairę“ reiškia saugumo praktikų integravimą kuo anksčiau į programinės įrangos kūrimo gyvavimo ciklą (SDLC). Tikslas yra rasti ir pašalinti pažeidžiamumus tada, kai tai yra pigiausia ir lengviausia – kūrimo metu.
Šiuolaikinė, saugi CI/CD konvejerio linija „TypeScript“ projektui turėtų atrodyti taip:
- Kūrėjo mašina: IDE papildiniai ir priešpatvirtinimo kabliai (pre-commit hooks) paleidžia linterius ir lengvus SAST nuskaitymus.
- Pateikiant (Commit)/Įkėlimo užklausa (Pull Request): CI serveris paleidžia išsamų SAST nuskaitymą ir SCA nuskaitymą. Jei aptinkami kritiniai pažeidžiamumai, kūrimas nepavyksta.
- Sujungus į testavimo (Staging) aplinką: Programa diegiama į testavimo aplinką. Tuomet CI serveris paleidžia DAST nuskaitymą prieš šią gyvą aplinką.
- Įdiegiant į gamybą: Po visų patikrų kodas diegiamas. Tolesnį stebėjimą ir vykdymo laiko apsaugos įrankius perima.
Praktiniai įrankiai ir įgyvendinimas
Teorija yra svarbi, tačiau praktinis įgyvendinimas yra esminis. Štai keletas įrankių ir metodų, kuriuos galite integruoti į savo „TypeScript“ kūrimo darbo eigą.
Esminiai ESLint saugumo papildiniai
ESLint yra galingas, konfigūruojamas „JavaScript“ ir „TypeScript“ linteris. Jį galite naudoti kaip lengvą, kūrėjams skirtą SAST įrankį, pridėdami saugumui skirtus papildinius:
- „eslint-plugin-security“: Aptinka dažnas „Node.js“ saugumo spąstus, tokius kaip „child_process.exec()“ naudojimas su neapdorotais kintamaisiais arba nesaugių reguliariųjų išraiškų (regex) šablonų aptikimas, kurie gali sukelti paslaugos atsisakymą (DoS).
- „eslint-plugin-no-unsanitized“: Teikia taisykles, padedančias išvengti XSS, žymint „innerHTML“, „outerHTML“ ir kitų pavojingų savybių naudojimą.
- Individualios taisyklės: Organizacijai skirtoms saugumo politikoms galite rašyti savo ESLint taisykles. Pavyzdžiui, galėtumėte parašyti taisyklę, draudžiančią importuoti pasenusią vidinę kriptografijos biblioteką.
CI/CD konvejerio integravimo pavyzdys („GitHub Actions“)
Čia pateikiamas supaprastintas „GitHub Actions“ darbo eigos pavyzdys, apjungiantis SCA ir SAST:
name: TypeScript Security Scan
on: [pull_request]
jobs:
security-check:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install dependencies
run: npm ci
- name: Run dependency audit (SCA)
# --audit-level=high fails the build for high-severity vulnerabilities
run: npm audit --audit-level=high
- name: Run security linter (SAST)
run: npx eslint . --ext .ts --quiet
# Example of integrating a more advanced SAST scanner like CodeQL
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: typescript
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
Už kodo ribų: vykdymo laiko ir architektūrinis saugumas
Visapusiškas auditas taip pat atsižvelgia į platesnę architektūrą ir vykdymo aplinką.
Tipų saugos API
Vienas geriausių būdų užkirsti kelią visoms klaidų klasėms tarp jūsų sąsajos ir vidinės dalies yra įdiegti tipų saugą visoje API riboje. Tokie įrankiai kaip tRPC, GraphQL su kodo generavimu (pvz., GraphQL Code Generator) arba OpenAPI generatoriai leidžia bendrinti tipus tarp jūsų kliento ir serverio. Jei pakeisite vidinės dalies API atsakymo tipą, jūsų „TypeScript“ sąsajos kodas nebus sukompiliuotas, taip išvengiant vykdymo laiko klaidų ir galimų saugumo problemų dėl nenuoseklių duomenų sutarčių.
Geriausia „Node.js“ praktika
Kadangi daugelis „TypeScript“ programų veikia „Node.js“, labai svarbu laikytis konkrečiai platformai skirtos geriausios praktikos:
- Naudokite saugumo antraštes: Naudokite bibliotekas, tokias kaip „helmet“ su Express, kad nustatytumėte svarbias HTTP antraštes (pvz., „Content-Security-Policy“, „X-Content-Type-Options“ ir kt.), kurios padeda sumažinti XSS ir kitų kliento pusės atakų riziką.
- Vykdyti su mažiausiomis privilegijomis: Neleiskite savo „Node.js“ proceso veikti kaip root vartotojui, ypač konteineryje.
- Nuolat atnaujinkite vykdymo aplinkas: Reguliariai atnaujinkite „Node.js“ ir „TypeScript“ versijas, kad gautumėte saugumo pataisymus.
Išvada ir veiksmingos išvados
„TypeScript“ suteikia fantastišką pagrindą patikimų ir prižiūrimų programų kūrimui. Tačiau saugumas yra atskira ir sąmoninga praktika. Tam reikalinga daugiasluoksnė gynybos strategija, apjungianti statinę kodo analizę, dinaminį vykdymo laiko testavimą ir budrų tiekimo grandinės valdymą.
Supratę dažniausiai pasitaikančius pažeidžiamumo tipus ir integravę tinkamus įrankius bei procesus į savo kūrimo gyvavimo ciklą, galite žymiai pagerinti savo „TypeScript“ programų saugumo būklę.
Veiksmingi žingsniai kūrėjams
- Įjunkite griežtą režimą: Savo „tsconfig.json“ faile nustatykite „\"strict\": true“. Tai įjungia tipų tikrinimo elgsenų rinkinį, kuris padeda išvengti dažnų klaidų.
- Tikrinkite savo kodą: Pridėkite „eslint-plugin-security“ prie savo projekto ir ištaisykite jo pranešamas problemas.
- Audituokite savo priklausomybes: Reguliariai vykdykite „npm audit“ arba „yarn audit“ ir nuolat atnaujinkite savo priklausomybes.
- Niekada nepasitikėkite vartotojo įvestimi: Visus duomenis, gaunamus iš jūsų programos išorės, laikykite potencialiai kenksmingais. Visada tinkamai patvirtinkite, valykite arba išskirkite juos tam kontekstui, kuriame jie bus naudojami.
Veiksmingi žingsniai komandoms ir organizacijoms
- Automatizuokite saugumą CI/CD: Integruokite SAST, DAST ir SCA nuskaitymus tiesiai į savo kūrimo ir diegimo konvejerio linijas. Nutraukite kūrimus aptikus kritinių pažeidžiamumų.
- Puoselėkite saugumo kultūrą: Reguliariai rengkite mokymus apie saugaus kodavimo praktiką. Skatinkite kūrėjus mąstyti gynybiškai.
- Atlikite rankinius auditus: Kritinėms programoms papildykite automatizuotus įrankius periodiniais rankiniais kodo peržiūromis ir penetracijos testavimu, atliekamu saugumo ekspertų.
Saugumas nėra funkcija, kurią reikia pridėti projekto pabaigoje; tai yra nuolatinis procesas. Priimdami proaktyvų ir daugiasluoksnį požiūrį į auditavimą, galite išnaudoti visą „TypeScript“ galią, kartu kurdami saugesnę, atsparesnę programinę įrangą pasaulinei vartotojų bazei.